import { type RefObject, useEffect, useState } from 'react';
import type { DataSourceArray } from 'photoswipe';
import useGallery from '@/hooks/useGallery';
import { useQuery } from '@tanstack/react-query';
import { queryFile } from '@/services/api';
import type { IClientFile } from '@/interfaces';
import { nanoid } from 'nanoid';
import { getImageSize } from '@/lib/tool';
import Clipboard from 'clipboard';
import { flushSync } from 'react-dom';

export default function useContentLayer({
  contentRef,
  appOssServer,
}: {
  contentRef: RefObject<HTMLDivElement>;
  appOssServer?: string;
}) {
  const [dataSource, setDataSource] = useState<DataSourceArray | any[]>([]);
  const galleryRef = useGallery({ dataSource });
  const [fileId, setFileId] = useState<string | null>(null);
  const queryFileQuery = useQuery(
    ['/file', fileId],
    async (context) => {
      return (await queryFile({
        id: context.queryKey[1] + '',
      })) as IClientFile;
    },
    {
      enabled: false,
    },
  );

  useEffect(() => {
    const fn = (e: Event) => {
      const target = e.target as Element;

      if (
        target.nodeName === 'I' &&
        target.classList.contains('yw-code-copy-btn')
      ) {
        copyCodeBlockToClipboard(target);
      } else if (
        target.nodeName === 'IMG' &&
        target.classList.contains('image')
      ) {
        handleImageClick(target);
      } else if (target.nodeName === 'SPAN' || target.nodeName === 'I') {
        if (
          target.parentElement &&
          target.parentElement.nodeName === 'A' &&
          target.parentElement.classList.contains('file')
        ) {
          handleAttachmentDownload(target.parentElement);
        }
      }
    };

    function copyCodeBlockToClipboard(el: Element) {
      const parentElement = el?.parentElement?.parentElement;
      const element = parentElement?.querySelector('pre code');

      if (!Clipboard.isSupported() || !element) {
        return;
      }

      try {
        el.classList.add('spinner-grow');
        Clipboard.copy(element);
        document.getSelection()?.empty();
      } finally {
        setTimeout(() => {
          el.classList.remove('spinner-grow');
        }, 500);
      }
    }

    function handleImageClick(target: Element) {
      const currentEl = contentRef.current;
      if (!currentEl) {
        return;
      }

      const parentElement = target.parentElement;
      const isImageLink = parentElement?.nodeName === 'A';
      if (isImageLink) {
        return;
      }

      const nodes = Array.from(currentEl.querySelectorAll('img.image'));
      const list = nodes
        .map((el, index) => {
          const id = nanoid();
          el.setAttribute('data-iid', id);
          el.setAttribute('data-index', `${index + 1}`);
          const src = el.getAttribute('src');
          const alt = el.getAttribute('alt');
          if (src) {
            return getImageSize(src, {
              id,
              element: el,
              src,
              alt: alt || 'img',
              msrc: src,
              index,
            });
          }
          return;
        })
        .filter(Boolean);

      Promise.all(list).then((value) => {
        const find = value.find(
          (item) => item.src === target.getAttribute('src'),
        );
        if (find) {
          galleryRef.current?.loadAndOpen(find.index, value);
        }
      });
    }

    async function handleAttachmentDownload(el: Element) {
      if (!appOssServer) {
        return;
      }

      const fileId = el.getAttribute('data-fid');
      if (!fileId) {
        return;
      }

      flushSync(() => {
        setFileId(fileId);
      });

      try {
        const response = await queryFileQuery.refetch({ throwOnError: true });
        const data = response.data;
        if (!data) {
          return;
        }

        const downloadUrl = appOssServer + data.urls.default;
        const fileName = data.originalName
          ? data.originalName + '.' + data.extension
          : 'file';
        download(downloadUrl, fileName);
      } catch (e) {
        console.error(e);
      }
    }

    async function download(url: string, download: string) {
      try {
        const res = await fetch(url);
        const blob = await res.blob();
        const aElement = document.createElement('a');
        aElement.style.display = 'none';
        aElement.setAttribute('download', download);
        const href = URL.createObjectURL(blob);
        aElement.href = href;
        aElement.setAttribute('target', '_blank');
        document.body.appendChild(aElement);
        aElement.click();
        setTimeout(() => {
          URL.revokeObjectURL(href);
          document.body.removeChild(aElement);
        }, 1000);
      } catch (e) {
        console.error(e);
      }
    }

    const current = contentRef.current;
    current?.addEventListener('click', fn);

    return () => {
      current?.removeEventListener('click', fn);
    };
  }, [contentRef, galleryRef, appOssServer, queryFileQuery]);
}
